package com.srmt.common.ratelimit.utils;

import java.lang.management.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * 性能指标收集器
 * 用于收集和分析限流器测试过程中的各种性能指标
 * 
 * @author SRMT Development Team
 * @since 1.0.0
 */
public class MetricsCollector {
    
    private static final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
    private static final MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
    private static final OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
    private static final RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
    
    private final ScheduledExecutorService scheduler;
    private final Map<String, MetricSeries> metrics;
    private final AtomicBoolean collecting;
    private final long startTime;
    private volatile ScheduledFuture<?> collectionTask;
    
    /**
     * 单个指标的时间序列数据
     */
    public static class MetricSeries {
        private final String name;
        private final String unit;
        private final List<DataPoint> dataPoints;
        private final Object lock = new Object();
        
        public MetricSeries(String name, String unit) {
            this.name = name;
            this.unit = unit;
            this.dataPoints = new ArrayList<>();
        }
        
        public void addValue(double value) {
            synchronized (lock) {
                dataPoints.add(new DataPoint(System.currentTimeMillis(), value));
            }
        }
        
        public void addValue(long timestamp, double value) {
            synchronized (lock) {
                dataPoints.add(new DataPoint(timestamp, value));
            }
        }
        
        public List<DataPoint> getDataPoints() {
            synchronized (lock) {
                return new ArrayList<>(dataPoints);
            }
        }
        
        public Statistics getStatistics() {
            synchronized (lock) {
                if (dataPoints.isEmpty()) {
                    return new Statistics(name, 0, 0, 0, 0, 0, 0);
                }
                
                List<Double> values = dataPoints.stream()
                    .map(dp -> dp.value)
                    .collect(Collectors.toList());
                    
                return new Statistics(
                    name,
                    values.stream().mapToDouble(Double::doubleValue).min().orElse(0),
                    values.stream().mapToDouble(Double::doubleValue).max().orElse(0),
                    values.stream().mapToDouble(Double::doubleValue).average().orElse(0),
                    calculatePercentile(values, 50),
                    calculatePercentile(values, 95),
                    calculatePercentile(values, 99)
                );
            }
        }
        
        private double calculatePercentile(List<Double> values, int percentile) {
            if (values.isEmpty()) return 0;
            Collections.sort(values);
            int index = (values.size() * percentile) / 100;
            return values.get(Math.min(index, values.size() - 1));
        }
        
        public void clear() {
            synchronized (lock) {
                dataPoints.clear();
            }
        }
    }
    
    /**
     * 数据点
     */
    public static class DataPoint {
        public final long timestamp;
        public final double value;
        
        public DataPoint(long timestamp, double value) {
            this.timestamp = timestamp;
            this.value = value;
        }
    }
    
    /**
     * 统计信息
     */
    public static class Statistics {
        public final String metricName;
        public final double min;
        public final double max;
        public final double avg;
        public final double p50;
        public final double p95;
        public final double p99;
        
        public Statistics(String metricName, double min, double max, double avg, 
                         double p50, double p95, double p99) {
            this.metricName = metricName;
            this.min = min;
            this.max = max;
            this.avg = avg;
            this.p50 = p50;
            this.p95 = p95;
            this.p99 = p99;
        }
        
        @Override
        public String toString() {
            return String.format("%s: min=%.2f, max=%.2f, avg=%.2f, p50=%.2f, p95=%.2f, p99=%.2f",
                metricName, min, max, avg, p50, p95, p99);
        }
    }
    
    /**
     * 构造函数
     */
    public MetricsCollector() {
        this.scheduler = Executors.newScheduledThreadPool(1, r -> {
            Thread t = new Thread(r, "MetricsCollector");
            t.setDaemon(true);
            return t;
        });
        this.metrics = new ConcurrentHashMap<>();
        this.collecting = new AtomicBoolean(false);
        this.startTime = System.currentTimeMillis();
        
        // 初始化默认指标
        initializeDefaultMetrics();
    }
    
    /**
     * 初始化默认指标
     */
    private void initializeDefaultMetrics() {
        registerMetric("heap_memory", "MB");
        registerMetric("non_heap_memory", "MB");
        registerMetric("cpu_usage", "%");
        registerMetric("thread_count", "count");
        registerMetric("gc_count", "count");
        registerMetric("gc_time", "ms");
    }
    
    /**
     * 注册一个新的指标
     */
    public void registerMetric(String name, String unit) {
        metrics.putIfAbsent(name, new MetricSeries(name, unit));
    }
    
    /**
     * 记录指标值
     */
    public void recordMetric(String name, double value) {
        MetricSeries series = metrics.get(name);
        if (series != null) {
            series.addValue(value);
        }
    }
    
    /**
     * 记录带时间戳的指标值
     */
    public void recordMetric(String name, long timestamp, double value) {
        MetricSeries series = metrics.get(name);
        if (series != null) {
            series.addValue(timestamp, value);
        }
    }
    
    /**
     * 开始自动收集系统指标
     */
    public void startAutoCollection(int intervalMs) {
        if (collecting.compareAndSet(false, true)) {
            collectionTask = scheduler.scheduleAtFixedRate(
                this::collectSystemMetrics, 0, intervalMs, TimeUnit.MILLISECONDS
            );
        }
    }
    
    /**
     * 停止自动收集
     */
    public void stopAutoCollection() {
        if (collecting.compareAndSet(true, false)) {
            if (collectionTask != null) {
                collectionTask.cancel(false);
                collectionTask = null;
            }
        }
    }
    
    /**
     * 收集系统指标
     */
    private void collectSystemMetrics() {
        // 内存指标
        MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
        MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage();
        
        recordMetric("heap_memory", heapUsage.getUsed() / 1024.0 / 1024.0);
        recordMetric("non_heap_memory", nonHeapUsage.getUsed() / 1024.0 / 1024.0);
        
        // CPU使用率
        if (osBean instanceof com.sun.management.OperatingSystemMXBean) {
            com.sun.management.OperatingSystemMXBean sunOsBean = 
                (com.sun.management.OperatingSystemMXBean) osBean;
            recordMetric("cpu_usage", sunOsBean.getProcessCpuLoad() * 100);
        }
        
        // 线程数
        recordMetric("thread_count", threadBean.getThreadCount());
        
        // GC统计
        List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
        long totalGcCount = 0;
        long totalGcTime = 0;
        
        for (GarbageCollectorMXBean gcBean : gcBeans) {
            totalGcCount += gcBean.getCollectionCount();
            totalGcTime += gcBean.getCollectionTime();
        }
        
        recordMetric("gc_count", totalGcCount);
        recordMetric("gc_time", totalGcTime);
    }
    
    /**
     * 创建QPS跟踪器
     */
    public QpsTracker createQpsTracker(String name) {
        registerMetric(name + "_qps", "req/s");
        registerMetric(name + "_success_rate", "%");
        return new QpsTracker(name);
    }
    
    /**
     * QPS跟踪器
     */
    public class QpsTracker {
        private final String name;
        private final AtomicLong successCount = new AtomicLong(0);
        private final AtomicLong failureCount = new AtomicLong(0);
        private final AtomicLong lastResetTime = new AtomicLong(System.currentTimeMillis());
        private final ScheduledFuture<?> trackingTask;
        
        QpsTracker(String name) {
            this.name = name;
            
            // 每秒计算一次QPS
            this.trackingTask = scheduler.scheduleAtFixedRate(() -> {
                long now = System.currentTimeMillis();
                long duration = now - lastResetTime.getAndSet(now);
                
                if (duration > 0) {
                    long success = successCount.getAndSet(0);
                    long failure = failureCount.getAndSet(0);
                    long total = success + failure;
                    
                    if (total > 0) {
                        double qps = (success * 1000.0) / duration;
                        double successRate = (success * 100.0) / total;
                        
                        recordMetric(name + "_qps", qps);
                        recordMetric(name + "_success_rate", successRate);
                    }
                }
            }, 1, 1, TimeUnit.SECONDS);
        }
        
        public void recordSuccess() {
            successCount.incrementAndGet();
        }
        
        public void recordFailure() {
            failureCount.incrementAndGet();
        }
        
        public void stop() {
            if (trackingTask != null) {
                trackingTask.cancel(false);
            }
        }
    }
    
    /**
     * 创建延迟跟踪器
     */
    public LatencyTracker createLatencyTracker(String name) {
        registerMetric(name + "_latency_avg", "ms");
        registerMetric(name + "_latency_p50", "ms");
        registerMetric(name + "_latency_p95", "ms");
        registerMetric(name + "_latency_p99", "ms");
        return new LatencyTracker(name);
    }
    
    /**
     * 延迟跟踪器
     */
    public class LatencyTracker {
        private final String name;
        private final List<Long> latencies = Collections.synchronizedList(new ArrayList<>());
        private final ScheduledFuture<?> analysisTask;
        
        LatencyTracker(String name) {
            this.name = name;
            
            // 每5秒分析一次延迟
            this.analysisTask = scheduler.scheduleAtFixedRate(() -> {
                List<Long> snapshot = new ArrayList<>(latencies);
                latencies.clear();
                
                if (!snapshot.isEmpty()) {
                    Collections.sort(snapshot);
                    
                    double avg = snapshot.stream().mapToLong(Long::longValue).average().orElse(0) / 1_000_000.0;
                    double p50 = snapshot.get(snapshot.size() * 50 / 100) / 1_000_000.0;
                    double p95 = snapshot.get(snapshot.size() * 95 / 100) / 1_000_000.0;
                    double p99 = snapshot.get(snapshot.size() * 99 / 100) / 1_000_000.0;
                    
                    recordMetric(name + "_latency_avg", avg);
                    recordMetric(name + "_latency_p50", p50);
                    recordMetric(name + "_latency_p95", p95);
                    recordMetric(name + "_latency_p99", p99);
                }
            }, 5, 5, TimeUnit.SECONDS);
        }
        
        public void recordLatency(long latencyNanos) {
            latencies.add(latencyNanos);
        }
        
        public void stop() {
            if (analysisTask != null) {
                analysisTask.cancel(false);
            }
        }
    }
    
    /**
     * 获取所有指标的当前统计
     */
    public Map<String, Statistics> getAllStatistics() {
        Map<String, Statistics> stats = new LinkedHashMap<>();
        for (Map.Entry<String, MetricSeries> entry : metrics.entrySet()) {
            stats.put(entry.getKey(), entry.getValue().getStatistics());
        }
        return stats;
    }
    
    /**
     * 获取特定指标的时间序列数据
     */
    public List<DataPoint> getTimeSeries(String metricName) {
        MetricSeries series = metrics.get(metricName);
        return series != null ? series.getDataPoints() : Collections.emptyList();
    }
    
    /**
     * 生成报告
     */
    public String generateReport() {
        StringBuilder report = new StringBuilder();
        report.append("\n========== 性能指标报告 ==========\n");
        report.append("收集时长: ").append((System.currentTimeMillis() - startTime) / 1000).append(" 秒\n\n");
        
        Map<String, Statistics> stats = getAllStatistics();
        
        // 系统指标
        report.append("【系统指标】\n");
        appendStatIfExists(report, stats, "heap_memory", "堆内存");
        appendStatIfExists(report, stats, "non_heap_memory", "非堆内存");
        appendStatIfExists(report, stats, "cpu_usage", "CPU使用率");
        appendStatIfExists(report, stats, "thread_count", "线程数");
        appendStatIfExists(report, stats, "gc_count", "GC次数");
        appendStatIfExists(report, stats, "gc_time", "GC时间");
        
        // QPS指标
        report.append("\n【QPS指标】\n");
        for (String key : stats.keySet()) {
            if (key.endsWith("_qps") || key.endsWith("_success_rate")) {
                Statistics stat = stats.get(key);
                report.append(String.format("  %s: 平均=%.2f, 最大=%.2f, 最小=%.2f\n",
                    key, stat.avg, stat.max, stat.min));
            }
        }
        
        // 延迟指标
        report.append("\n【延迟指标】\n");
        for (String key : stats.keySet()) {
            if (key.contains("_latency_")) {
                Statistics stat = stats.get(key);
                report.append(String.format("  %s: %.2fms\n", key, stat.avg));
            }
        }
        
        return report.toString();
    }
    
    /**
     * 辅助方法：添加统计信息到报告
     */
    private void appendStatIfExists(StringBuilder report, Map<String, Statistics> stats, 
                                   String metricName, String displayName) {
        Statistics stat = stats.get(metricName);
        if (stat != null) {
            report.append(String.format("  %s: 平均=%.2f, 最大=%.2f, 最小=%.2f\n",
                displayName, stat.avg, stat.max, stat.min));
        }
    }
    
    /**
     * 导出CSV格式的时间序列数据
     */
    public String exportToCsv(String metricName) {
        MetricSeries series = metrics.get(metricName);
        if (series == null) {
            return "";
        }
        
        StringBuilder csv = new StringBuilder();
        csv.append("Timestamp,Value\n");
        
        for (DataPoint dp : series.getDataPoints()) {
            csv.append(dp.timestamp).append(",").append(dp.value).append("\n");
        }
        
        return csv.toString();
    }
    
    /**
     * 清理所有数据
     */
    public void clear() {
        for (MetricSeries series : metrics.values()) {
            series.clear();
        }
    }
    
    /**
     * 关闭收集器
     */
    public void shutdown() {
        stopAutoCollection();
        scheduler.shutdown();
        try {
            scheduler.awaitTermination(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}